import asunit.framework.TestCase;

import mockAS2.Matcher;
import mockAS2.SpyMethod;
import mockAS2.mocks.ClassToBeMocked;

/**
 * Copyright (c) 2012 Gary Higham
 * Released under the MIT license
 * https://code.google.com/p/mock-as2/wiki/License
 *
 * Version: v0.1
 */
class mockAS2.SpyMethodTest extends TestCase {
	private var className : String = "tvpTestFramework.SpyMethodTest";
	private var dummy : ClassToBeMocked;
	private var spy : SpyMethod;
	private var methodArg1 : String = "A String";
	
	public function SpyMethodTest(testMethod : String) {
		super(testMethod);
	}
	
	public function setUp() : Void {
		dummy = new ClassToBeMocked();
		spy = new SpyMethod(dummy, "return1");
	}
	
	public function teadDown() : Void {
		delete dummy;
		dummy = null;
		
		delete spy;
		spy = null;	
	}
	
	public function testSpyMethodCanSpyOnSingleMethodCall() : Void {
		callMethod(1);
		assertEquals("1 method call should have been detected by spy", true, spy.calledOnce());
	}
	
	public function testSpyMethodCanSpyOnTwoMethodCalls() : Void {
		callMethod(2);
		assertEquals("2 method calls should have been detected by spy", true, spy.calledTwice());
	}
	
	public function testSpyMethodCanSpyOnMultipleMethodCalls() : Void {
		callMethod(10);
		assertEquals("10 method calls should have been detected by spy", 10, spy.getCallCount());
	}
	
	public function testMethodUnderSpyFunctionsAsNormal() : Void {
		assertEquals("return1 method should return1", 1, dummy.return1());
	}
	
	public function testSpyOnExactSingleMethodArgs() : Void {
		dummy.return1(methodArg1);
		assertEquals("The method should have been called with: ", true, spy.calledWithExactArgs(methodArg1));
	}
	
	public function testSpyOnExactArgsWhichAreIncorrectByContent() : Void {
		dummy.return1(methodArg1);
		assertEquals("The method should not have been called with Wrong", false, spy.calledWithExactArgs("Wrong"));
	}
	
	public function testSpyOnExactArgsWhichAreIncorrectByNumber() : Void {
		dummy.return1(methodArg1);
		assertEquals("The method should not have been called with 2 args", false, spy.calledWithExactArgs(methodArg1, "Wrong"));
	}
	
	public function testSpyOnExactMultipleMethodArgs() : Void {
		dummy.return1(methodArg1, 2, false);
		assertEquals("The method should have been called with: ", true, spy.calledWithExactArgs(methodArg1, 2, false));
	}
	
	public function testSpyOnMethodWithArgs() : Void {
		dummy.return1(methodArg1, 2, false);
		assertTrue("The first argument should have been: " + methodArg1, spy.calledWithArgs(methodArg1));
	}
	
	public function testSpyOnMethodWithArgsIncorrectByContent() : Void {
		dummy.return1(methodArg1, 2, false);
		assertFalse("The method should not have been called with Args: " + methodArg1 + " and 4", spy.calledWithArgs(methodArg1, 4));
	}
	
	public function testSpyOnMethodWithMoreArgsThanPassed() : Void {
		dummy.return1(methodArg1);
		assertFalse("This should not have been called with Args: " + methodArg1 + " and 4", spy.calledWithArgs(methodArg1, 4));
	}
	
	public function testMatchingInstanceOfObjectCalled() : Void {
		var matcher : Matcher = new Matcher();
		var spyOnMatcher : SpyMethod = new SpyMethod(matcher, "performMatch");
		dummy.return1(new ClassToBeMocked());
		spy.calledWithExactArgs(matcher);
		assertTrue("When passing a Matcher comparisons should be made using matcher performMatch", spyOnMatcher.calledOnce());
	}
	
	public function testRestoreStopsSpyOnObject() : Void {
		spy.restore();
		callMethod(1);
		assertFalse("Spy should not be monitoring behaviour", spy.calledOnce());
	}

	private function callMethod(times : Number) : Void {
		while(times > 0) {
			dummy.return1();
			times--;
		}
	}
}
